#ifndef DIR_SYNCER_H_
#define DIR_SYNCER_H_

#include "../interfaces/Useroutputinterface.h"
#include "../interfaces/MessageHandlerInterface.h"
#include "../interfaces/ConnStatInterface.h"
#include "interfaces/SyncUpdatedInterface.h"
#include "../Userdatabase.h"
#include "../Transport.h"
#include "../Filetransfer.h"
#include "../FileInfo.h"
#include "Sync.h"

using namespace std;
using boost::filesystem::path;

typedef map<string, SyncPtr> SyncMap;


class Dir_syncer : public MessageHandlerInterface, SyncUpdatedInterface, ConnStatInterface
{
public:

    /** transport message subtypes **/
    typedef enum _SyncSubtypes
    {
      UNDEFINED = 0,
      INIT = 1,
      OFFER = 2,
      CANCEL = 3,
      CANCEL_ACK = 4,
      CONTINUE_REQUEST = 5,
      CONTINUE_ACK = 6
    } SyncSubtypes;


    Dir_syncer(Userdatabase* users, Transport* trans, Filetransfer* filetransfer);
    virtual ~Dir_syncer();


    // initiate new sync
    void initiate_push_sync(UserPtr partner, string minePath);
    void initiate_pull_sync(UserPtr partner, string theirPath);



    // MessageHandlerInterface
    virtual void handleMessage(TransportMessage* msg, TransportMessage::MESSAGE_TYPE type, uint8_t subtype, UserPtr user);

    // SyncUpdatedInterface
    virtual void sync_updated_callback(SyncPtr sync);
    virtual void activate_transfers_callback(boost::shared_ptr<Sync> sync);

    // ConnStatInterface  (User connected/disconnected)
    virtual void got_connection_update(UserPtr user, bool connected);


private:
    // returns new unique tag
    string create_unique_tag(SyncPtr sync);

    // adds new sync into database, fails if key isn't unique
    bool add_sync(SyncPtr syn);

    // sync_init handlers
    void got_push_sync_init(SyncPtr sync);
    void got_pull_sync_init(SyncPtr sync);

    // find tag in sync_db, throws exception if not found
    SyncPtr get_sync_from_db(SyncPtr sync);
    SyncPtr get_sync_from_db(string base_tag, UserPtr user);
    SyncPtr _get_sync_from_db(string composed_tag);
    // drop sync from db
    SyncPtr drop_sync_from_db(string base_tag, UserPtr user);
    SyncPtr _drop_sync_from_db(string composed_tag);

    // send a not yet transferred file in this sync   XXX das kommt wohl weg!
    void send_next_file(SyncPtr sync);


    /** handler for incoming packets **/
    void got_init(TransportMessage* msg, UserPtr user);
    void got_offer(TransportMessage* msg, UserPtr user);
    void got_cancel(TransportMessage* msg, UserPtr user);

    /** for ConnStatInterface **/
    void user_connected(UserPtr user);
    void user_disconnected(UserPtr user);


private:
    Useroutputinterface* ui;
    Userdatabase* users;
    Transport* trans;
    Filetransfer* filetransfer;

    SyncMap sync_db;
};

#endif /* DIR_SYNCER_H_ */
